#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include "Personnage.h"
#include <math.h>


using namespace std;

//Mutateur


void setTypePers(Personnage *Pers, typePers typeP)
{
    Pers->typeP = typeP;
}
void setNom (Personnage *Pers, char nom[100])
{
    strcpy(Pers->nom ,nom);
}
void setDir(Personnage* Pers , Direction dir)
{
    Pers->dir = dir;
}

void setCaract(Personnage *Pers , int caract[10])
{
    for(int i = 0 ; i < 10 ; i ++)
    {
        Pers->caract[i] = caract[i];
    }
}

void setInventaire(Personnage *Pers, Objet entite, int x)
{

    Pers->inventaire[x] = entite;

}

void setPosition (Personnage *Pers, int x , int y)
{
    setPosX(&Pers->pos, x);
    setPosY(&Pers->pos, y);
}

void setCaract (Personnage *Pers, int caract , int valeur)
{
    Pers->caract[caract] = valeur;
}

//Accesseur

typePers getTypePers(Personnage *Pers)
{
    return Pers->typeP;
}

const char* getNom(const Personnage *Pers)
{
    return Pers->nom;
}

Objet* getInventaire(const Personnage *Pers , int type)
{
    return (Objet*)&Pers->inventaire[type];
}

Objet* getInventaire(const Personnage *Pers)
{
    return (Objet*)&Pers->inventaire;
}

Position* getPosition( const Personnage *Pers)
{
    return (Position*)&Pers->pos;
}

int getCaract (const Personnage *Pers , type caract)
{
    return Pers->caract[caract];
}


int getArmure(const Personnage *Pers)
{
    int armure = 0;
    for(int i = 0 ; i < 5 ; i ++)
    {
        armure += getArmure(&Pers->inventaire[i]);
    }
    return armure;
}

int getBonus(Personnage *Pers , type_Carac type)
{
    int bonus = 0;
    for(int i = 0 ; i < 5 ; i ++)
    {
        if( getTypeBonus(getBonus(&Pers->inventaire[i]))== type )
            bonus += getValeurBonus(getBonus(&Pers->inventaire[i]));
    }
    return bonus;
}

Direction getDir(Personnage *Pers)
{
    return Pers->dir;
}

//Fonction

void InitPers(Personnage *Pers, char nom[100], int x, int y, typePers typeP)
{
    strcpy(Pers->nom ,nom);
    setPosX(&Pers->pos, x);
    setPosY(&Pers->pos, y);
    Pers->typeP = typeP;

    Pers->dir = BAS;

    for(int i = 0 ; i< TAILLE_INVENTAIRE ; i ++)
    {
        initObj(&Pers->inventaire[i]);
    }
}

void Deplacer(Personnage *Pers , Direction dir , int TailleDeplacement)
{
    switch(dir)
    {
    case HAUT:
        setPosY(&Pers->pos , getPosY(&Pers->pos )- TailleDeplacement );
        break;
    case BAS:
        setPosY(&Pers->pos , getPosY(&Pers->pos )+ TailleDeplacement );
        break;
    case DROITE:
        setPosX(&Pers->pos , getPosX(&Pers->pos )+ TailleDeplacement );
        break;
    case GAUCHE:
        setPosX(&Pers->pos , getPosX(&Pers->pos )- TailleDeplacement );
        break;
    }
}

ResultAttaque Attaque(Personnage *Attaquant , Personnage *Defenseur)
{
    int agiA = getCaract(Attaquant ,AGILITE )+ getBonus(Attaquant, AGILITE);
    int forceA = getCaract(Attaquant , FORCE) + getBonus(Attaquant, FORCE);
    int intellA = getCaract(Attaquant, INTELLIGENCE) + getBonus(Attaquant, INTELLIGENCE);

    int agiD = getCaract(Defenseur ,AGILITE )+ getBonus(Defenseur, AGILITE);
    int forceD = getCaract(Defenseur , FORCE) + getBonus(Defenseur, FORCE);
    int intellD = getCaract(Defenseur, INTELLIGENCE) + getBonus(Defenseur, INTELLIGENCE);

    int vie = getCaract(Defenseur , VIE_A);
    int degats = getDegats(getInventaire(Attaquant , ARME)) + agiA;
    int armure = getArmure(Defenseur) + intellD/2;
    int exp = getCaract(Attaquant, EXP);
    int Or = getCaract(Attaquant,OR);
    int niveauA = getCaract(Attaquant, NIVEAU);
    int niveauD = getCaract(Defenseur, NIVEAU);
    int diffExp = 0;
    int expWin = 0;
    int orWin = 0;

    ResultAttaque retour;
    retour.degats = 0;
    retour.levelup = 0;

    int coup_critique,rate;
    int attaque;

    int ecart_degats, ecart_armure;

    if(vie > 0 )
    {
        if(degats != 0)
            ecart_degats= rand()% degats/10 + (-degats/10) ;
        else
            ecart_degats = 0;

        if(armure != 0)
            ecart_armure= rand()% armure/10 + armure/5;
        else
            ecart_armure = 0;

        attaque = (degats + ecart_degats) - (ecart_armure);

        if(attaque <=0)
            attaque = 1;

        retour.degats = attaque;

        coup_critique= rand()% 10 ;
        if(coup_critique == 3)
        {
            attaque*=3;
            cout<<"Coup critique"<<endl;
        }
        cout<<attaque<<" D: "<<degats + ecart_degats<<" A: "<<armure + ecart_armure<<endl;
        setCaract(Defenseur ,VIE_A, vie - attaque);

        if(getCaract(Defenseur , VIE_A)<= 0)
        {
            expWin = (niveauD*50)*(1.0+(0.5*agiA)/100);
            setCaract(Defenseur ,VIE_A, 0);
            setCaract(Attaquant, EXP, (exp + expWin));
            while((exp = getCaract(Attaquant, EXP))>(niveauA*niveauA*100))
            {

                diffExp = exp - (niveauA*niveauA*100);
                setCaract(Attaquant, EXP, diffExp);
                niveauA ++;

                retour.levelup++;
            }
            orWin = (niveauD*niveauD*10)*(1.0+(0.5*forceA)/100);
            setCaract(Attaquant, OR, (Or + orWin));
        }
    }

    return retour;
}

void EquiperObjet(Personnage* Pers, int objet)
{
    Objet *Obj1, *Obj2 ;
    Objet *Obj;

    Obj = new Objet;

    Obj1 = getInventaire(Pers,objet );

    if(getNiveau(Obj1) <= getCaract(Pers , NIVEAU) && getTypeObjet(Obj1) != POTION && getTypeObjet(Obj1) != RIEN)
    {
        if(getTypeObjet(Obj1) == EPEE || getTypeObjet(Obj1) == HACHE || getTypeObjet(Obj1) == BATON || getTypeObjet(Obj1) == ARC)
            Obj2 = getInventaire(Pers,ARME);
        else
            Obj2 = getInventaire(Pers,getTypeObjet(getInventaire(Pers,objet )));


        if(getTypeBonus(getBonus(Obj2)) == FORCE)
        {
            setCaract(Pers , VIE  , getCaract(Pers,VIE) - (20*getValeurBonus(getBonus(Obj2))));
            setCaract(Pers , VIE_A  , getCaract(Pers,VIE_A ) - (20*getValeurBonus(getBonus(Obj2))));
            if(getCaract(Pers , VIE_A ) <= 0)
                setCaract(Pers , VIE_A  ,1 );
        }
        else if(getTypeBonus(getBonus(Obj2)) == INTELLIGENCE)
        {
            setCaract(Pers , MANA , getCaract(Pers, MANA) - (10*getValeurBonus(getBonus(Obj2))));
            setCaract(Pers , MANA_A  , getCaract(Pers, MANA_A ) - (10*getValeurBonus(getBonus(Obj2))));
            if(getCaract(Pers , MANA) < 0)
                setCaract(Pers , MANA_A  ,0 );
        }

        if(getTypeBonus(getBonus(Obj1)) == FORCE)
        {
            setCaract(Pers , VIE  , getCaract(Pers,VIE) + (20*getValeurBonus(getBonus(Obj1))));
            setCaract(Pers , VIE_A  , getCaract(Pers,VIE_A ) + (20*getValeurBonus(getBonus(Obj1))));
        }
        else if(getTypeBonus(getBonus(Obj1)) == INTELLIGENCE)
        {
            setCaract(Pers , MANA , getCaract(Pers, MANA) + (10*getValeurBonus(getBonus(Obj1))));
            setCaract(Pers , MANA_A  , getCaract(Pers, MANA_A ) + (10*getValeurBonus(getBonus(Obj1))));
        }


        AffecteObjet(Obj ,Obj1);
        AffecteObjet(Obj1,Obj2);
        AffecteObjet(Obj2 ,Obj);

    }
    else if (getTypeObjet(Obj1) == POTION )
    {
        utiliserPotion(Pers,Obj1);
    }

    delete Obj;
}

void ReplaceObjetInventaire(Personnage *Pers , Objet * Obj)
{
    int i = 5;
    Objet* ObjTemp , *ObjNull;
    ObjTemp = new Objet;

    while( i < TAILLE_INVENTAIRE && getTypeObjet(getInventaire(Pers , i)) != RIEN )
    {

        i++;
    }

    ObjNull = getInventaire(Pers , i);

    if(getTypeObjet(ObjNull) == RIEN && i != TAILLE_INVENTAIRE)
    {
        if(getTypeBonus(getBonus(Obj)) == FORCE)
        {
            setCaract(Pers , VIE  , getCaract(Pers,VIE) - (20*getValeurBonus(getBonus(Obj))));
            setCaract(Pers , VIE_A  , getCaract(Pers,VIE_A ) - (20*getValeurBonus(getBonus(Obj))));
            if(getCaract(Pers , VIE_A ) <= 0)
                setCaract(Pers , VIE_A  ,1 );
        }
        else if(getTypeBonus(getBonus(Obj)) == INTELLIGENCE)
        {
            setCaract(Pers , MANA , getCaract(Pers, MANA) - (10*getValeurBonus(getBonus(Obj))));
            setCaract(Pers , MANA_A  , getCaract(Pers, MANA_A ) - (10*getValeurBonus(getBonus(Obj))));
            if(getCaract(Pers , MANA) < 0)
                setCaract(Pers , MANA_A  ,0 );
        }


        AffecteObjet(ObjTemp ,Obj);
        AffecteObjet(Obj,ObjNull);
        AffecteObjet(ObjNull ,ObjTemp);
    }
    delete ObjTemp;

}


void utiliserPotion (Personnage *Pers, Objet *Obj)
{
    if (getTypeRest(getRestauration(Obj)) == VIE)
    {
        if(((getCaract(Pers, VIE_A)) + getValeurRest(getRestauration(Obj))) < (getCaract(Pers, VIE)))
        {
            setCaract(Pers, VIE_A, getValeurRest(getRestauration(Obj)) + (getCaract(Pers, VIE_A))) ;
            initObj(Obj);
        }
        else if((getCaract(Pers, VIE_A)) == (getCaract(Pers, VIE)))
        {
            setCaract(Pers,VIE_A, getCaract(Pers, VIE)) ;
        }
        else
        {
            setCaract(Pers,VIE_A, getCaract(Pers, VIE)) ;
            initObj(Obj);
        }
    }
    else if (getTypeRest(getRestauration(Obj)) == MANA)
    {
        if(((getCaract(Pers, MANA_A)) + getValeurRest(getRestauration(Obj))) < (getCaract(Pers, MANA)))
        {
            setCaract(Pers, MANA_A, getValeurRest(getRestauration(Obj)) + (getCaract(Pers, MANA_A))) ;
            initObj(Obj);
        }
        else if((getCaract(Pers, MANA_A)) == (getCaract(Pers, MANA)))
        {
            setCaract(Pers,MANA_A, getCaract(Pers, MANA)) ;
        }
        else
        {
            setCaract(Pers,MANA_A, getCaract(Pers, MANA)) ;
            initObj(Obj);
        }
    }
}
